package com.jule.chat.network;

import com.jule.chat.config.Config;
import com.jule.chat.network.handler.BinaryWebSocketFrameHandler;
import com.jule.chat.network.handler.ChatWebSocketFrameHandler;
import com.jule.chat.network.handler.FunctionHandler;
import com.jule.core.network.handler.WsRequestHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import io.netty.util.concurrent.EventExecutorGroup;
import io.netty.util.internal.PlatformDependent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by xujian on 2016/8/6.
 */
public class WSIOServer {
    private static final ServerBootstrap bootstrap = new ServerBootstrap();
    private static final EventExecutorGroup EVENT_EXECUTORS = new DefaultEventExecutorGroup(Runtime.getRuntime().availableProcessors());
    private final static Logger logger = LoggerFactory.getLogger(WSIOServer.class);

    public static void connect() {
        // Configure the server.
        EventLoopGroup bossGroup = PlatformDependent.isWindows() ? new NioEventLoopGroup(1) : new EpollEventLoopGroup(1);
        EventLoopGroup workerGroup = PlatformDependent.isWindows() ? new NioEventLoopGroup(Runtime.getRuntime().availableProcessors()) : new EpollEventLoopGroup(Runtime.getRuntime().availableProcessors());
        try {
            bootstrap.group(bossGroup, workerGroup).channel(PlatformDependent.isWindows() ? NioServerSocketChannel.class : EpollServerSocketChannel.class)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .childOption(ChannelOption.SO_REUSEADDR, true)
                    .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 15 * 1000)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast("logger", new LoggingHandler(LogLevel.DEBUG));
                            pipeline.addLast(new HttpServerCodec());
                            pipeline.addLast(new HttpObjectAggregator(64 * 1024));
                            pipeline.addLast(new ChunkedWriteHandler());
                            pipeline.addLast(new WsRequestHandler("/chat"));
                            pipeline.addLast(new WebSocketServerProtocolHandler("/chat"));
                            pipeline.addLast(new ChatWebSocketFrameHandler());
                            pipeline.addLast(new BinaryWebSocketFrameHandler());
                            pipeline.addLast(EVENT_EXECUTORS, new FunctionHandler());
                        }
                    });

            bootstrap.bind(Config.BIND_PORT).sync();
            LoggerFactory.getLogger(WSIOServer.class).info("service bind port " + Config.BIND_PORT);

        } catch (Exception e) {
            LoggerFactory.getLogger(WSIOServer.class).error("", e);
        }
    }

}
